using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Drawing.Design;
using System.Linq;
using System.Windows.Forms;

namespace ALPControls
{
    [ProvideProperty("Action", typeof(Component))]
    public partial class ActionListProvider : Component, IExtenderProvider, ISupportInitialize
    {
        private Dictionary<Component, Action> _actionDictionary = new Dictionary<Component, Action>();
        private ActionCollection _actionCollection = new ActionCollection();

        #region Constructor
        public ActionListProvider()
        {
            InitializeComponent();
            _actionCollection.Provider = this;
        }

        public ActionListProvider(IContainer container)
        {
            container.Add(this);
            InitializeComponent();
            _actionCollection.Provider = this;
        }
        #endregion

        #region IExtenderProvider Members

        public bool CanExtend(object extendee)
        {
            return (extendee is ButtonBase) || (extendee is ToolStripItem);
        }

        #endregion

        [Description("Select an action")]
        [Category("Behaviour")]
        public Action GetAction(Component cmp)
        {
            return _actionDictionary.ContainsKey(cmp) ? _actionDictionary[cmp] : null;
        }

        public void SetAction(Component cmp, Action act)
        {
            _actionDictionary.Remove(cmp);
            if (act == null) return;
            _actionDictionary.Add(cmp, act);
            UpdateEnabled(act);
            UpdateText(act);
            AddExecuteTarget(act);
        }

        [Category("Actions")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Editor(typeof(ActionCollectionEditor), typeof(UITypeEditor))]
        public ActionCollection Actions
        {
            get { return _actionCollection; }
        }

        internal void UpdateEnabled(Action act)
        {
            foreach (var actionLink in _actionDictionary.Where(actionLink => actionLink.Value == act))
            {
                if (actionLink.Key is ButtonBase)
                    ((ButtonBase)actionLink.Key).Enabled = act.Enabled;
                if (actionLink.Key is ToolStripItem)
                    ((ToolStripItem)actionLink.Key).Enabled = act.Enabled;
            }
        }

        internal void UpdateText(Action act)
        {
            foreach (var actionLink in _actionDictionary.Where(actionLink => actionLink.Value == act))
            {
                if (actionLink.Key is ButtonBase)
                    ((ButtonBase)actionLink.Key).Text = act.Text;
                if (actionLink.Key is ToolStripItem)
                    ((ToolStripItem)actionLink.Key).Text = act.Text;
            }
        }

        internal void AddExecuteTarget(Action act)
        {
            if (act.ExecuteHandlers == null) return;
            RemoveExecuteTarget(act);
            var target = (EventHandler)act.ExecuteHandlers.GetInvocationList()[0];
            foreach (var actionLink in _actionDictionary.Where(actionLink => actionLink.Value == act))
            {
                if (actionLink.Key is ButtonBase)
                    ((ButtonBase)actionLink.Key).Click += target;
                if (actionLink.Key is ToolStripItem)
                    ((ToolStripItem)actionLink.Key).Click += target;
            }
        }

        internal void RemoveExecuteTarget(Action act)
        {
            if (act.ExecuteHandlers == null) return;
            var target = (EventHandler)act.ExecuteHandlers.GetInvocationList()[0];
            foreach (var actionLink in _actionDictionary.Where(actionLink => actionLink.Value == act))
            {
                if (actionLink.Key is ButtonBase)
                    ((ButtonBase)actionLink.Key).Click -= target;
                if (actionLink.Key is ToolStripItem)
                    ((ToolStripItem)actionLink.Key).Click -= target;
            }
        }


        #region ISupportInitialize Members

        public void BeginInit()
        {
        }

        public void EndInit()
        {
            foreach (Action act in Actions)
            {
                UpdateEnabled(act);
                UpdateText(act);
                AddExecuteTarget(act);
            }
        }

        #endregion
    }
}